<template>
  <vxe-pulldown
    class="rk-tree-select"
    ref="vxePullDownRef"
    v-model="pulldownVisible"
    :disabled="disabled"
    @hide-panel="handlePullDownHide"
  >
    <template #default>
      <el-input
        readonly
        type="text"
        ref="selectInputRef"
        v-model="selectValue"
        :title="selectValue"
        :disabled="disabled"
        :placeholder="placeholder"
        @click="echoInputClick"
        @mouseover="setSelectInputHover(true)"
        @mouseleave="setSelectInputHover(false)"
      >
        <template #suffix>
          <template v-if="selectHoverVisible && clearable && modelValue">
            <el-icon
              @click="clearSelectValue">
              <CircleClose />
            </el-icon>
          </template>
          <template v-else>
            <el-icon
              @mouseover="setSelectInputHover(true)"
              @mouseleave="setSelectInputHover(false)"
            >
              <caret-top v-if="pulldownVisible"/>
              <caret-bottom v-else/>
            </el-icon>
          </template>
        </template>
      </el-input>
    </template>
    <template #dropdown>
      <div class="rk-tree-select-dropdown">
        <div class="rk-tree-select-dropdown-search" v-show="filterable">
          <el-input
            ref="searchInputRef"
            v-model="searchValue"
            prefix-icon="search"
            :placeholder="filterPlaceholder"
          >
          <template #suffix>
            <span class="clear-icon">
              <el-icon @click="searchValue = ''"><CircleClose /></el-icon>
            </span>
          </template>
          </el-input>
        </div>
        <div class="rk-tree-select-dropdown-content">
          <el-tree
            ref="treeRef"
            :="$attrs"
            :data="treeData"
            :node-key="localProps.value"
            :props="localProps"
            :highlight-current="true"
            :filter-node-method="filterTreeNode"
            @node-click="handleNodeClick"
          >
          </el-tree>
        </div>
      </div>
    </template>
  </vxe-pulldown>
</template>

<script setup name="RkTreeSelect">
import { getDistData } from "@/api/api-dist"
import { EnumsDataPools } from '@/enums/enums-index.js'
import { CommonUtils, TreeSelectUtils } from './common/select-utils'
import { nextTick } from "vue"
import IsUtils from '@/utils/is-utils.js'
import XEUtils from "xe-utils"

const props = defineProps({
  // 用于v-model
  modelValue: { type: [String, Number] },
  // 节点配置信息
  props: {
    type: Object, default: () => {
      return {
        label: "label",
        value: "value",
        children: "children",
        disabled: "disabled"
      }
    }
  },
  // 传入数据
  data: { type: Array, default: () => ([]) },
  // 字典类型 String | Object: { name: '', params: {},}
  dist: { type: [String, Object], default: '' },
  // 本地字典
  enum: { type: [String, Object], default: '' },
  // 自定义请求
  server: { type: [Function] },
  // 是否展示编码
  showCode: { type: Boolean, default: true },
  // 是否禁用
  disabled: { type: Boolean, default: false },
  // 是否清空
  clearable: { type: Boolean, default: true },
  // 提示语
  placeholder: { type: String, default: '请选择' },
  // 是否可搜索
  filterable: { type: Boolean, default: true },
  // 搜索框提示语
  filterPlaceholder: { type: String, default: '输入关键字进行过滤' },
  // 父节点是否可以选中
  parentNodeSelected: { type: Boolean, default: true },
  // 是否选中节点后关闭下拉容器
  closePanelNodeSelected: { type: Boolean, default: true }
})

// 用于定义v-model
const emits = defineEmits([
  'update:modelValue', // 用于定义v-model
  'change'
])

// 初始化加载
onMounted(() => {
  loadTreeData()
})
watch(
  () => props.modelValue,
  (newValue, oldValue) => {
    setSelectValue()
  }
)

// 下拉容器的模板引用
const vxePullDownRef = ref()
// 下拉容器是否展示
const pulldownVisible = ref(false)

// ----- vxe-pulldown相关
/**
 * 在下拉面板被触发隐藏时触发该事件
 */
const handlePullDownHide = () => {
  // 设置显示输入框划过状态
  setSelectInputHover(false)
  // 下拉面板隐藏
  pulldownVisible.value = false
  // 展示输入框失去焦点
  selectInputRef.value.blur()
  // 重置搜索内容
  searchValue.value = ''
  // 重置树节点选中
  resetTreeSelect()
}
// 监听下拉面板展开状态
watch(
  pulldownVisible,
  (newValue, oldValue) => {
    if (newValue) {
      // 设置树节点选中
      setTreeSelect()
      // 设置搜索输入框获取焦点
      setSearchInputFocus()
    }
  }
)

// ----- 展示的输入框相关
const selectValue = ref('')
const selectInputRef = ref()
// 展示输入框鼠标是否划过
const selectHoverVisible = ref(false)
/** 展示输入库点击触发 */
const echoInputClick = function () {
  pulldownVisible.value = !pulldownVisible.value
}
/** 设置展示输入框的值（select回显内容）*/
const setSelectValue = function () {
  if (IsUtils.isNotEmpty(props.modelValue)) {
    const data = treeNodeMap.value[props.modelValue]
    if (data) {
      selectValue.value = data[localProps.label]
    }
  }
}
/** 点击清除图标 */
const clearSelectValue = function () {
  selectValue.value = ''
  emitModelValue('', false)
  resetTreeSelect()
}
/**
 * 设置鼠标是否划过展示输入框
 * @param {Boolean} value 状态值
 */
const setSelectInputHover = function (value) {
  selectHoverVisible.value = value
}

// ----- 搜索的输入框相关
const searchValue = ref('')
const searchInputRef = ref()
/**
 * 搜索查询内容
 * @param {String} value 查询内容
 */
const handleSearch = async function (value) {
  treeRef.value.filter(value)
}
/** 设置搜索输入框获取焦点 */
const setSearchInputFocus = () => {
  nextTick(() => {
    searchInputRef.value.focus()
  })
}
/** 监听搜索内容 */
watch(
  searchValue,
  (newValue, oldValue) => {
    handleSearch(newValue)
  }
)

// ----- 树形结构相关
const treeRef = ref()
const treeData = ref([])
const localProps = reactive(props.props)
const treeNodeMap = ref({})
const treeExpandMap = ref({})
/**
 * 加载树结构数据：优先级：data > dist > enum > server
 */
const loadTreeData = async () => {
  treeData.value = []
  let result = []
  if (props.data && props.data.length > 0) {
    result = dealStaticData()
  } else if (props.dist) {
    result = await dealBaseData()
  } else if (props.enum) {
    result = dealEnumData()
  } else if (props.server) {
  }
  // 设置树结构数据
  setTreeData(result)
}
// ----- 处理基础数据相关
/** 处理基础数据 */
const dealBaseData = async () => {
  if (!props.dist) return
  const { dist } = props
  // 处理tree的props
  localProps.label = 'name'
  localProps.value = 'code'
  // 检查传递的参数
  const msg = CommonUtils.validateDist(dist)
  if (msg) {
    console.error(msg)
    return
  }
  // 获取查询参数
  const params = CommonUtils.getDistQueryParams(dist)
  // 请求数据
  const result = await loadBaseData(params)
  return result
}
/**
 * 加载基础数据
 * @param {Object} params 查询参数
 */
const loadBaseData = (params) => {
  return new Promise(reslove => {
    getDistData(params).then(res => {
      const { code, data, msg } = res
      if (code === 200) {
        reslove(data)
      } else {
        console.error(msg)
        reslove([])
      }
    }).catch(err => {
      console.error(err)
      reslove([])
    })
  })
}
// ----- 处理本地静态数据
const dealEnumData = () => {
  if ((props.enum instanceof String || typeof props.enum === 'string') && props.enum) {
    const enumOptions = XEUtils.clone(EnumsDataPools[props.enum].options, true)
    const result = Object.keys(enumOptions).map(key => {
      return enumOptions[key]
    })
    // 设置数据
    return result
  } else {
    console.error('属性enum需要为字符串类型，且不为空！')
    return []
  }
}
// ----- 处理静态数据相关
const dealStaticData = () => {
  return props.data
}
/**
 * 设置树结构数据
 * @param {Array} result 树结构数据
 */
const setTreeData = (result) => {
  const { parseData, expandMap, nodeMap } = TreeSelectUtils.transfData(result, { showCode: props.showCode, props: toRaw(localProps) })
  treeData.value = parseData
  treeNodeMap.value = nodeMap
  treeExpandMap.value = expandMap
  setSelectValue()
}
/**
 * 树结构查询
 * @param {String} value 查询内容
 * @param {Object} data 树节点
 */
const filterTreeNode = (value, data) => {
  if (!value) return true
  return data[localProps.label].includes(value)
}
/**
 * 设置树结构选中
 */
const setTreeSelect = () => {
  // 设置默认数据回显
  if (props.modelValue) {
    nextTick(() => {
      treeRef.value.setCurrentKey(props.modelValue)
    })
  }
}
/**
 * 重置树结构选中项
 */
const resetTreeSelect = () => {
  if (treeRef.value) {
    treeRef.value.setCurrentKey(null)
  }
}
/** 树节点点击 */
const handleNodeClick = (data, node, config, event) => {
  const { parentNodeSelected } = props
  if (parentNodeSelected) {
    emitModelValue(data)
  } else {
    if (data[localProps.children] && data[localProps.children].length > 0) {
      return
    } else {
      emitModelValue(data)
    }
  }
}
/**
 * 向上触发设置选中值
 *
 * @param {Object} data 节点数据
 */
const emitModelValue = (data, closePanel = true) => {
  emitChange(data)
  emits('update:modelValue', data[localProps.value])
  if (props.closePanelNodeSelected && closePanel) {
    handlePullDownHide()
  }
}

/**
 * 向上触发内容改变事件
 * @param {Object} data 选中节点数据
 */
const emitChange = (data) => {
  if (data) {
    emits('change', data[localProps.value], toRaw(treeData.value))
  } else {
    emits('change', '')
  }
}

</script>

<style lang="scss" scoped>
.rk-tree-select {
  width: 100%;
  :deep(.vxe-pulldown--panel) {
    z-index: 99999 !important
  }
}
.rk-tree-select-dropdown {
  // border: 1px solid #dcdfe6;
  // border-radius: 4px;
  .rk-tree-select-dropdown-search {
    :deep(.el-input__wrapper) {
      border-radius: 4px 4px 0 0;
    }
  }
  .rk-tree-select-dropdown-content {
    min-height: 100px;
    max-height: 300px;
    overflow: auto;
    border: 1px solid #dcdfe6;
    border-top: none;
    .clear-icon {
      cursor: pointer;
    }
  }
}
</style>
